using System.Linq;
using Moq;
using NUnit.Framework;
using OpenWaves.Pagination;
using OpenWaves.Web.Pagination;

namespace OpenWaves.UnitTests.Web.Pagination
{
    [TestFixture]
    public class PaginationViewModelBuilderTests
    {
        [Test]
        public void When_PageCollection_is_empty_VisiblePages_is_empty()
        {
            var paginationViewModel = PaginationViewModel.Create(0, Enumerable.Empty<IPage<int>>(), 0);

            Assert.That(paginationViewModel.VisiblePages, Is.Empty);
        }

        [Test]
        public void When_PageCollection_is_empty_all_page_references_are_null()
        {
            var paginationViewModel = PaginationViewModel.Create(0, Enumerable.Empty<IPage<int>>(), 0);

            Assert.IsNull(paginationViewModel.CurrentPage);
            Assert.IsNull(paginationViewModel.FirstPage);
            Assert.IsNull(paginationViewModel.LastPage);
            Assert.IsNull(paginationViewModel.NextPage);
            Assert.IsNull(paginationViewModel.PreviousPage);            
        }

        [Test]
        public void Given_PageCollection_contains_one_page_When_showing_first_page_PaginationViewModel_is_correct()
        {
            const int currentPageIndex = 0;
            var paginationViewModel = PaginationViewModel.Create(5, new[] { CreatePageMock(0, 4) }, currentPageIndex);

            Assert.IsNotNull(paginationViewModel.CurrentPage);
            Assert.IsNotNull(paginationViewModel.FirstPage);
            Assert.IsNotNull(paginationViewModel.LastPage);

            Assert.AreEqual(paginationViewModel.CurrentPage, paginationViewModel.FirstPage);
            Assert.AreEqual(paginationViewModel.FirstPage, paginationViewModel.LastPage);

            Assert.That(paginationViewModel.VisiblePages, Is.EquivalentTo(new[] { paginationViewModel.CurrentPage }));

            Assert.IsNull(paginationViewModel.PreviousPage);
            Assert.IsNull(paginationViewModel.NextPage);

            Assert.That(paginationViewModel.CurrentPage.Number, Is.EqualTo(1));
            Assert.That(paginationViewModel.CurrentPage.FirstItemNumber, Is.EqualTo(1));
            Assert.That(paginationViewModel.CurrentPage.LastItemNumber, Is.EqualTo(5));
        }

        [Test]
        public void Given_PageCollection_contains_two_pages_When_showing_first_page_PaginationViewModel_is_correct()
        {
            const int currentPageIndex = 0;
            var paginationViewModel = PaginationViewModel.Create(10, new[] { CreatePageMock(0, 4), CreatePageMock(5, 9) }, currentPageIndex);

            Assert.IsNotNull(paginationViewModel.CurrentPage);
            Assert.IsNotNull(paginationViewModel.FirstPage);
            Assert.IsNotNull(paginationViewModel.LastPage);

            Assert.AreEqual(paginationViewModel.CurrentPage, paginationViewModel.FirstPage);
            Assert.AreEqual(paginationViewModel.NextPage, paginationViewModel.LastPage);

            Assert.That(paginationViewModel.VisiblePages, Is.EquivalentTo(new[] { paginationViewModel.FirstPage, paginationViewModel.LastPage }));

            Assert.IsNull(paginationViewModel.PreviousPage);
        }

        [Test]
        public void Given_PageCollection_contains_two_pages_When_showing_second_page_PaginationViewModel_is_correct()
        {
            const int currentPageIndex = 1;
            var paginationViewModel = PaginationViewModel.Create(10, new[] { CreatePageMock(0, 4), CreatePageMock(5, 9) }, currentPageIndex);

            Assert.IsNotNull(paginationViewModel.CurrentPage);
            Assert.IsNotNull(paginationViewModel.FirstPage);
            Assert.IsNotNull(paginationViewModel.LastPage);

            Assert.AreEqual(paginationViewModel.CurrentPage, paginationViewModel.LastPage);
            Assert.AreEqual(paginationViewModel.PreviousPage, paginationViewModel.FirstPage);

            Assert.That(paginationViewModel.VisiblePages, Is.EquivalentTo(new[] { paginationViewModel.FirstPage, paginationViewModel.LastPage }));

            Assert.IsNull(paginationViewModel.NextPage);
        }

        [Test]
        public void When_currentPageIndex_is_out_of_bounds_LastPage_is_assumed_to_be_the_current_page()
        {
            const int currentPageIndex = 10;
            var paginationViewModel = PaginationViewModel.Create(10, new[] { CreatePageMock(0, 4), CreatePageMock(5, 9) }, currentPageIndex);

            Assert.IsNotNull(paginationViewModel.CurrentPage);
            Assert.IsNotNull(paginationViewModel.FirstPage);
            Assert.IsNotNull(paginationViewModel.LastPage);

            Assert.AreEqual(paginationViewModel.CurrentPage, paginationViewModel.LastPage);
            Assert.AreEqual(paginationViewModel.PreviousPage, paginationViewModel.FirstPage);

            Assert.That(paginationViewModel.VisiblePages, Is.EquivalentTo(new[] { paginationViewModel.FirstPage, paginationViewModel.LastPage }));

            Assert.IsNull(paginationViewModel.NextPage);
        }

        private static IPage<int> CreatePageMock(int firstItemIndex, int lastItemIndex)
        {
            var firstPageMock = new Mock<IPage<int>>();
            firstPageMock.Setup(p => p.FirstItemIndex).Returns(firstItemIndex);
            firstPageMock.Setup(p => p.LastItemIndex).Returns(lastItemIndex);
            return firstPageMock.Object;
        }
    }
}